// pkg/fanotify/listener.go
package fanotify

import (
	"context"
	"fmt"
	"log"
	"os"
	"sync"
	"syscall"
	"unsafe"

	"golang.org/x/sys/unix"
)

// Listener fanotify 事件监听器
type Listener struct {
	fd   int
	mu   sync.Mutex
	done chan struct{}

	// 事件处理回调
	handlers map[string]EventHandler
}

// EventHandler 事件处理函数
type EventHandler func(ctx context.Context, event *Event) error

// Event 代表一个 fanotify 事件
type Event struct {
	Mask      uint64 // FAN_ACCESS, FAN_OPEN 等
	Fd        int
	Filename  string
	Timestamp int64
}

const (
	// FAN_MARK_RECURSIVE is missing in x/sys/unix
	FAN_MARK_RECURSIVE = 0x00000100
	// FAN_NOFD is used to indicate no file descriptor
	FAN_NOFD = -1
)

// FanotifyEvent represents a fanotify_event_metadata structure.
type FanotifyEvent struct {
	Event_len uint32
	Vers      uint8
	Reserved  uint8
	Metadata_len uint16
	Mask      uint64
	Fd        int32
	Pid       int32
}

// Next returns the next fanotify event in the buffer or nil if there are no more events.
func (e *FanotifyEvent) Next(buf []byte) *FanotifyEvent {
	nextOffset := int(e.Event_len)
	if nextOffset < int(unsafe.Sizeof(FanotifyEvent{})) || nextOffset >= len(buf) {
		return nil
	}
	nextEvent := (*FanotifyEvent)(unsafe.Pointer(&buf[nextOffset]))
	if nextEvent.Event_len == 0 {
		return nil
	}
	return nextEvent
}

// ParseFanotifyEvent parses fanotify events from a buffer.
func ParseFanotifyEvent(buf []byte) *FanotifyEvent {
	if len(buf) < int(unsafe.Sizeof(FanotifyEvent{})) {
		return nil
	}
	event := (*FanotifyEvent)(unsafe.Pointer(&buf[0]))
	if event.Event_len == 0 {
		return nil
	}
	return event
}

// NewListener 创建 fanotify 监听器
func NewListener() (*Listener, error) {
	// 创建 fanotify 文件描述符
	// FAN_CLASS_NOTIF: 只读通知，不支持权限事件
	// FAN_NONBLOCK: 非阻塞
	fd, err := unix.FanotifyInit(unix.FAN_CLASS_NOTIF|unix.FAN_NONBLOCK, unix.O_RDONLY)
	if err != nil {
		return nil, fmt.Errorf("fanotify_init failed: %w", err)
	}

	l := &Listener{
		fd:       fd,
		done:     make(chan struct{}),
		handlers: make(map[string]EventHandler),
	}

	return l, nil
}

// Watch 监视指定目录/文件
func (l *Listener) Watch(path string, handler EventHandler) error {
	l.mu.Lock()
	defer l.mu.Unlock()

	// FAN_MARK_ADD: 添加到现有标记
	// FAN_MARK_RECURSIVE: 递归监视子目录
	// FAN_EVENT_ON_CHILD: 监视子项变化
	mask := uint64(unix.FAN_OPEN | unix.FAN_ACCESS | unix.FAN_CLOSE)

	err := unix.FanotifyMark(
		l.fd,
		unix.FAN_MARK_ADD|FAN_MARK_RECURSIVE,
		mask,
		unix.AT_FDCWD,
		path,
	)
	if err != nil {
		return fmt.Errorf("fanotify_mark failed for %s: %w", path, err)
	}

	l.handlers[path] = handler
	return nil
}

// Unwatch 停止监视
func (l *Listener) Unwatch(path string) error {
	l.mu.Lock()
	defer l.mu.Unlock()

	err := unix.FanotifyMark(
		l.fd,
		unix.FAN_MARK_REMOVE,
		0,
		unix.AT_FDCWD,
		path,
	)
	if err != nil {
		return fmt.Errorf("fanotify_mark remove failed: %w", err)
	}

	delete(l.handlers, path)
	return nil
}

// Start 启动事件监听循环
func (l *Listener) Start(ctx context.Context) error {
	go l.eventLoop(ctx)
	return nil
}

// eventLoop 主事件处理循环
func (l *Listener) eventLoop(ctx context.Context) {
	buf := make([]byte, 4096)

	for {
		select {
		case <-l.done:
			return
		case <-ctx.Done():
			return
		default:
		}

		// 非阻塞读取事件
		n, err := syscall.Read(l.fd, buf)
		if err != nil {
			if err == unix.EAGAIN || err == unix.EWOULDBLOCK {
				// 没有事件，继续
				continue
			}
			log.Printf("fanotify read error: %v", err)
			continue
		}

		if n <= 0 {
			continue
		}

		// 解析事件
		metadata := ParseFanotifyEvent(buf[:n])
		for metadata != nil {
			event := &Event{
				Mask: metadata.Mask,
				Fd:   int(metadata.Fd),
			}

			// 获取文件路径
			if metadata.Fd != FAN_NOFD {
				fdPath := fmt.Sprintf("/proc/self/fd/%d", metadata.Fd)
				filename, _ := os.Readlink(fdPath)
				event.Filename = filename
			}

			// 触发处理器
			l.handleEvent(ctx, event)

			// 移动到下一个事件
			metadata = metadata.Next(buf)
		}
	}
}

// handleEvent 处理单个事件
func (l *Listener) handleEvent(ctx context.Context, event *Event) {
	l.mu.Lock()
	handler, exists := l.handlers[""] // 全局处理器
	l.mu.Unlock()

	if exists && handler != nil {
		if err := handler(ctx, event); err != nil {
			log.Printf("event handler error: %v", err)
		}
	}
}

// Close 关闭监听器
func (l *Listener) Close() error {
	l.mu.Lock()
	defer l.mu.Unlock()

	close(l.done)
	return unix.Close(l.fd)
}

// ---